<!-- html节点选择器，类似chrome f12选择元素工具 -->
<template>
  <div class="node-picker">
    <el-button
      class="addSelector"
      :link="true"
      type="primary"
      @click="startElementSelection()"
    >
      <span class="selector_text" :title="$demoi18n('low-code-linkage.selectingAnElement')">{{ $demoi18n('low-code-linkage.selectingAnElement') }}</span>
      <Helptip>{{ $demoi18n('low-code-linkage.selectElTip') }}</Helptip>
    </el-button>
  </div>
</template>
<script>
import { getCssPath, isPopupChild } from '@/components/common/low-code/low-code-util.js';
import EventBus from '@/event-bus/EventBus.js';
import { bindVisibleChange } from '@/utils/util.js';
import Helptip from '@/components/common/helptip/helptip.vue';
export default {
  components: { Helptip },
  inject: {
    panelWid: {
      default: '',
    },
  },
  props: {
    cssPath: {
      type: String,
      default: '',
    },
  },
  emits: ['onSelect'],
  data() {
    return {
      timer: null,
      compEl: null,
      cssPath_: '',
      cssEl: null,
      prevEls: [],
    };
  },
  watch: {
    cssPath: {
      handler(val) {
        this.cssPath_ = val;
      },
      immediate: true,
    },
  },
  created() {},
  mounted() {
    bindVisibleChange(this.$el, () => {
      EventBus.$emit(`curPreviewVm_${this.panelWid}`);
    });
  },
  beforeUnmount() {
    this.stopElementSelection();
  },
  methods: {
    startElementSelection() {
      EventBus.$emit(`curPreviewVm_${this.panelWid}`);

      // 代码检视： 判断window.visualComp.curPreviewVm 是否有实例值
      this.compEl = window.visualComp.curPreviewVm.$el;
      this.compEl.classList.add('node-picker-comp-box');
      document.body.classList.add('node-picking');

      if (this.cssPath_) {
        this.compEl.querySelectorAll(this.cssPath_).forEach(n1 => {
          n1.classList.add('node-picker-hover');
        });
      }

      setTimeout(() => {
        window.addEventListener('mousemove', this.hoverElement);
        window.addEventListener('click', this.selectElement);
        window.addEventListener('keyup', this.selectElementByKeyup);
      }, 20);
    },
    stopElementSelection() {
      this.clearPickerHoverCss();
      this.compEl?.classList?.remove('node-picker-comp-box');
      document.body.classList.remove('node-picking');

      window.removeEventListener('mousemove', this.hoverElement);
      window.removeEventListener('click', this.selectElement);
      window.removeEventListener('keyup', this.selectElementByKeyup);
    },
    hoverElement(event) {
      clearTimeout(this.timer);
      this.timer = setTimeout(() => {
        const el = event.target;
        this.highlightElement(el);
      }, 50);
    },
    highlightElement(el) {
      this.clearPickerHoverCss();
      const isChild = (this.compEl.contains(el) && el !== this.compEl);
      const isPopChild = isPopupChild(el, this.compEl, this.panelWid);
      if (isChild || isPopChild) {
        el.classList.add('node-picker-hover');
        el.classList.add('node-picker-current');
        this.cssPath_ = getCssPath(el, this.compEl, this.panelWid);
        this.cssEl = el;
        if (this.cssPath_) {
          this.compEl.querySelectorAll(this.cssPath_).forEach(n1 => {
            n1.classList.add('node-picker-hover');
          });

          document.body.querySelectorAll(`.el-popper ${this.cssPath_}`).forEach(n1 => {
            n1.classList.add('node-picker-hover');
          });
        }
      }
    },
    selectElementByKeyup(event) {
      event.preventDefault();

      // 方向键“左”
      if (event.keyCode === 37) {
        let el = this.cssEl.previousElementSibling;
        if (!el) {
          el = this.cssEl.parentNode.firstElementChild;
        }
        this.highlightElement(el);
        return;
      }

      // 方向键“右”
      if (event.keyCode === 39) {
        let el = this.cssEl.nextElementSibling;
        if (!el) {
          el = this.cssEl.parentNode.firstElementChild;
        }
        this.highlightElement(el);
        return;
      }

      // 方向键“上”
      if (event.keyCode === 38) {
        const el = this.cssEl.parentElement;
        const isChild = (this.compEl.contains(el) && el !== this.compEl);
        const isPopChild = isPopupChild(el, this.compEl, this.panelWid);

        if (isChild || isPopChild) {
          this.prevEls.push(this.cssEl);
          this.highlightElement(el);
        }
        return;
      }

      // 方向键“下”
      if (event.keyCode === 40) {
        const el = this.prevEls.pop();
        if (el) {
          this.highlightElement(el);
        }
        return;
      }

      // 回车
      if (event.keyCode === 13) {
        this.selectElement(null, true);
        return;
      }

      // Esc键取消
      if (event.keyCode === 27) {
        this.selectElement(null, false);
      }
    },
    clearPickerHoverCss() {
      const arr = ['node-picker-hover', 'node-picker-current'];
      arr.forEach(n => {
        document.body.querySelectorAll(`.${n}`).forEach(n1 => {
          n1.classList.remove(n);
        });
      });
    },
    selectElement(e, doSelect = true) {
      if (e) { // 点击区域组件下拉框时不要提交返回弹窗
        const excludes = ['regions-tree-current-name'];
        const isExclude = excludes.some(n => e.srcElement.classList.contains(n));
        if (isExclude) {
          return;
        }
      }

      const el = this.cssEl;

      const isChild = (this.compEl.contains(el) && el !== this.compEl);
      const isPopChild = isPopupChild(el, this.compEl, this.panelWid);

      if ((isChild || isPopChild) && doSelect) {
        this.$emit('onSelect', { el, cssPath: this.cssPath_ });
      }

      // 停止元素选择
      this.stopElementSelection();
    },

  },
};
</script>
<style lang="less" scoped>
.node-picker{
  display: inline-block;
  .selector_text{
    overflow: hidden;
    width: 60px;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
}
</style>
<style lang="less">
.node-picker-hover{
  outline: 1px dashed green !important;
}
.node-picker-current{
  outline: 1px dashed tan !important;
}
.node-picker-comp-box{
  box-shadow: 0 0 0px 3px #f56c6c;
}
body.node-picking{
  .el-overlay{
    display: none;
  }
}
</style>
